package cRpc

import (
	"fmt"
	"reflect"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"

	"gitee.com/csingo/cComponents"
	"gitee.com/csingo/cLog"
)

type RpcComponent struct{}

func (i *RpcComponent) Inject(instance any) bool {
	if service_container.Is(instance) {
		service_container.Save(instance)
		return true
	}
	if client_container.Is(instance) {
		client_container.Save(instance)
		return true
	}

	return false
}

func (i *RpcComponent) InjectConf(config cComponents.ConfigInterface) bool {
	if config.ConfigName() == RpcConfigName {
		temp := config.(*RpcConf)
		temp.SignEncryptFunc = rpc_config.SignEncryptFunc
		temp.SignDecryptFunc = rpc_config.SignDecryptFunc
		temp.HostFunc = rpc_config.HostFunc
		rpc_config = temp
		return true
	}
	if config.ConfigName() == MetadataConfigName {
		temp := config.(*MetadataConf)

		if reflect.ValueOf(temp.Context).Kind() == reflect.Struct {
			metadata_config = temp
		}

		return true
	}

	return false
}

func (i *RpcComponent) Load() {
	var hosts = make(map[string]string)
	var conns = make(map[string]grpc.ClientConnInterface)

	// 设置 http request uri
	if rpc_config.RequestURI == "" {
		rpc_config.RequestURI = HTTPRequestUri
	}

	// 设置 http 超时时间
	if rpc_config.Timeout <= 0 {
		rpc_config.Timeout = HTTPTimeout
	}

	// 设置 http 请求次数
	if rpc_config.Try <= 0 {
		rpc_config.Try = HTTPTryTimes
	}

	// 组装 hosts 和 grpc connection
	for _, client := range rpc_config.Clients {
		if len(client.Services) == 0 {
			continue
		}

		var conn grpc.ClientConnInterface
		var err error
		if client.Type == GRPCClient {
			conn, err = grpc.NewClient(client.Host, grpc.WithTransportCredentials(insecure.NewCredentials()))
			if err != nil {
				cLog.WithContext(nil, map[string]any{
					"source": "cRpc.RpcConf.SetHosts",
					"host":   client.Host,
					"err":    err.Error(),
				}).Error("GRPC 连接失败")
				continue
			}
			cLog.WithContext(nil, map[string]any{
				"source": "cRpc.RpcConf.SetHosts",
				"host":   client.Host,
			}).Trace("GRPC 连接成功")
		}

		for _, service := range client.Services {
			index := fmt.Sprintf("%s.%s.%s", client.Package, service.App, service.Service)
			hosts[index] = client.Host
			if client.Type == GRPCClient {
				conns[index] = conn
			}
		}
	}

	client_container.hosts = hosts
	client_container.grpc = conns
}

func (i *RpcComponent) Listen() []*cComponents.ConfigListener {
	return []*cComponents.ConfigListener{
		{
			ConfigName: RpcConfigName,
			Listeners: []cComponents.ListenHandler{
				listener,
			},
		},
	}
}

func listener(config cComponents.ConfigInterface) {
	Component.InjectConf(config)
	Component.Load()
}

var Component = &RpcComponent{}
